/**
 * Created by gim on 14-1-23.
 */

var fs = require('fs');
require('./model_setting.js');


/**
 *  create the model config and
 *  return the function added model
 * @param path
 * @param db
 * @param instance
 * @param template
 */
function requireMapping(path,db,instance,template){
    var currentDb = checkDbAndReturn(db);
    var _model = Model.createNew(path,currentDb,instance,template);
    global[_model.className] = require('./model_import.js')(_model);
    return global[_model.className];
}

/**
 * return the db module
 * if db is null,
 * throw a db Error
 * @param db
 * @returns {*|Function|db|db|db|db}
 */
function checkDbAndReturn(db){
    if(db == null && global.db == null){
        throw new Error('db cant be null');
    }
    return (db || global.db);
}

/**
 * add the .js files for the folder require
 * @param root
 * @returns {Array}
 */
function getAllFiles(root) {
    var res = [] , files = fs.readdirSync(root);
    files.forEach(function (file) {
        var pathname = root + '/' + file
            , stat = fs.lstatSync(pathname);

        if (!stat.isDirectory()) {
            //only support .js files
            if (pathname.search(/\.js/) > -1) {
                res.push(pathname);
            }
        } else {
            res = res.concat(getAllFiles(pathname));
        }
    });
    return res;
}

/**
 * this function will get all the file paths
 * and return the relatively path
 * @param root
 * @param files
 * @returns {{}}
 */
function getModelPaths(root,files){
    var modelPaths = {};
    var pathName;
    for (var  i=0;i<files.length;i++){
        pathName = files[i].replace(root+'/','').split('.')[0];
        if (pathName.search(/_/) > -1){
           pathName = pathName.replace('_','').toLowerCase();
        }
        modelPaths[pathName] = files[i];
    }
    return modelPaths;
}

/**
 *  require file enter without template
 * @param path
 * @param db
 * @returns {*}
 */
function m_require(path,db){
    var model = require(path);
    return requireMapping(path,db,model,null);
}

/**
 *  require file enter with custom template
 * @param path
 * @param db
 * @param template
 * @returns {*}
 */
function cm_require(path,db,template){
    var model = require(path);
    return requireMapping(path,db,model,template);
}

/**
 *  require file enter with custom template
 * @param modelName
 * @param option : {db: db, template: template}
 * @returns {*}
 */
function loadModel(modelName, option,modelPaths){
    var path =  modelPaths[modelName.toLowerCase()];
    return loadModelByPath(path,option);
}

/**
 * require model by path
 * @param path
 * @param option
 * @returns {*}
 */
function loadModelByPath(path,option){
    if (option == null || typeof option == 'undefined'){
        option = {};
        option.db = null;
    }
    if ( typeof option.template != 'undefined') {
        return cm_require(path, option.db, option.template);
    }
    return m_require(path, option.db);
}

/**
 * lazy model load
 * @param modelPaths
 * @param db
 */
function loadModels (modelPaths,option) {
    for(var key in modelPaths){
        loadModelByPath(modelPaths[key], option);
    }
}

/*********************************
 *   exports module api          *
 *********************************
 */


exports.extTemplate = function(templateObj){
    global._cusTemplate = require(templateObj);
};

/**
 * load model folder, you can select lazyLoad model by arguments[1] = true
 * @param path
 * @param isLazyLoad
 * @param db
 * @returns string
 */
exports.loadFolder = function (path, option) {
    if (typeof global._modelPaths == 'undefined') {
        global._modelPaths = getModelPaths(path, getAllFiles(path));
    }
    var lazy = false;
    if (typeof option.lazy != 'undefined'){
        lazy = option.lazy;
    }
    if (!lazy) {
        loadModels(global._modelPaths,option);
    }
    global._options = option;
};


exports.loadModel = function(){
    var path = arguments[0];
    var option = arguments[1];
    var modelPaths = global._modelPaths;
    if (typeof option == 'undefined'){
        option = global._options;
    }
    if (typeof  modelPaths == 'undefined' || path.search(/\//) > -1){
       return loadModelByPath(path,option);
    }
    // path is model name
    return loadModel(path,option,modelPaths);
};